package org.com.yz.dubbo.service.impl;

import cn.hutool.core.date.DateTime;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.StringUtil;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.com.yz.common.config.ConfigureTest;
import org.com.yz.common.config.IPostService;
import org.com.yz.common.config.ServiceName;
import org.com.yz.common.util.*;
import org.com.yz.dal.dao.mapper.DepositTransactionMapper;
import org.com.yz.dal.dao.mapper.MchAccntMapper;
import org.com.yz.dal.dao.mapper.WithDrawInfoMapper;
import org.com.yz.dal.dao.model.*;
import org.com.yz.dubbo.api.service.IPresentQueryService;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;

/**
 * @ClassName PresentQueryServiceImpl
 * @Author wzc
 * @Date 2018/7/27 9:48
 **/
@Service(version = "1.0.0")
public class PresentQueryServiceImpl implements IPresentQueryService {


    private static Logger log = LoggerFactory.getLogger(PresentQueryServiceImpl.class);

    @Autowired
    private MchAccntMapper mchAccntMapper;

    @Autowired
    private DepositTransactionMapper depositTransactionMapper;


    @Autowired
    private WithDrawInfoMapper withDrawInfoMapper;


    private static final MyLog _log = MyLog.getLog(PresentQueryServiceImpl.class);


    public PresentQuery presentHandle(PresentQueryEs presentQueryEs) {

        PresentQuery resad = new PresentQuery( );
        PresentQuery presentQuery = presentQueryEs.getBizContent( );
        MchConfig config = CacheUtil.me( ).getMchConfigInfo(presentQueryEs.getMchNo( ),"0");
        //MchConfig config = new MchConfig();
        String mchNo = presentQueryEs.getMchNo( );
        HashMap<String, String> paramMap = new HashMap<>( );
        paramMap.put("timestamp", DateUtil.getSeqString( ));
        paramMap.put("appid", config.getApp_id( ));
        paramMap.put("service", ServiceName.getPresentQuery( ));
        paramMap.put("ver", "02");
        paramMap.put("sign_type", ServiceName.getSign_typeRsa( ));
        paramMap.put("order_no", presentQuery.getOrderNo( ));
        paramMap.put("mac", Signature.generateMAC(paramMap, mchNo));
        String result = IPostService.txn(ConfigureTest.isDevEnv( ) ? ConfigureTest.PAYMENT : ConfigureTest.PY_PROD_API, paramMap, mchNo);  //发送请求
        _log.info("提现查询收付直通车返回" + result);
        JSONObject jsonObjecta = (JSONObject) JSONObject.parse(result);  //转换为json

        resad.setChannel(presentQuery.getChannel( ));
        resad.setMchAccntNo(presentQuery.getMchAccntNo( ));
        resad.setCardNo(presentQuery.getCardNo( ));
        resad.setOrderNo(presentQuery.getOrderNo( ));
        if (result.contains("errcode")) {  //代表失败
            resad.setStatus("2");  //返回失败
            resad.setErrmsg((String) jsonObjecta.get("errmsg"));
        }
        if (result.contains("sno") && result.contains("transStatus")) {  //代表返回成功
            String status = (String) jsonObjecta.get("transStatus");  //交易状态
            String trans_date = (String) jsonObjecta.get("transDate");  //付 款 日 期
            String trans_time = (String) jsonObjecta.get("transTime"); //付 款 时 间
            String trans_fee = (String) jsonObjecta.get("transFee");  //交易手续费
            String amount = (String) jsonObjecta.get("transAmt");  //付款金额
            String orderNo = (String) jsonObjecta.get("orderNo");  //订单号
            String card_no = (String) jsonObjecta.get("toAcctNo");  //银行卡号


            if ("1".equals(status)) {        //交易成功
                MchAccnt mchAccnt = new MchAccnt( );
                mchAccnt.setMchAccntNo(presentQueryEs.getBizContent( ).getMchAccntNo( ));
                mchAccnt.setAccntType("mchsub");
                List<MchAccnt> resa = mchAccntMapper.selectMchAccnt(mchAccnt);
                if (resa.size( ) > 0) {
                    Long accnt_amt_after = resa.get(0).getRemainAmt( );
                    resad.setAccntAmtAfter(String.valueOf(accnt_amt_after));    //成功返回账户余额，其他只返回明细
                }
            }
            resad.setStatus(status);
            resad.setOutOrderNo(orderNo);
            resad.setTransDate(trans_date);
            resad.setTransTime(trans_time);
            resad.setTransFee(AmountUtil.convertDollar2Cent(trans_fee));
            resad.setAmount(AmountUtil.convertDollar2Cent(amount));
            resad.setCardNo(card_no);

            insertTra(presentQueryEs.getMchNo( ), presentQueryEs.getOutTransNo( ), presentQueryEs.getBizType( ));

        }

        return resad;

    }


    /**
     * @param
     * @Description:
     * @author wzc
     * @date 2018/8/17 11:03
     */
    public void insertTra(String mcnNo, String traNo, String type) {

        DepositTransaction depositTransaction = new DepositTransaction( );
        depositTransaction.setMchNo(mcnNo);
        depositTransaction.setTransactionNo(UUID.randomUUID( ).toString( ).replace("-", "").toLowerCase( ));//事务号
        depositTransaction.setOutTransNo(traNo);//外部追踪号
        depositTransaction.setIdMchAccntChargeUp(0);
        depositTransaction.setCreateTime(new DateTime( ));//创建时间
        depositTransaction.setTransactionType(type);//事务类型
        depositTransaction.setUpdateTime(new DateTime( ));//更新时间
        //更新事务表
        depositTransactionMapper.insert(depositTransaction);
    }


    /**
     * @param
     * @Description:
     * @author wzc
     * @date 2018/8/16 11:35
     */
    public PresentQuery withdrawPayQuery(PresentQueryEs presentQueryEs) throws Exception {
        PresentQuery payQuery = presentQueryEs.getBizContent( );
        PresentQuery presentQuery = null;
        MchConfig mchConfig = new MchConfig( );
        mchConfig.setMchNo(presentQueryEs.getMchNo( ));
        MchConfig config = CacheUtil.me( ).getMchConfigInfo(presentQueryEs.getMchNo( ),"0");   //查询商户配置
        if (null == config) {
            payQuery.setErrmsg("无配置信息");
            payQuery.setStatus("2");
            return payQuery;
        }
//        String sno = withDrawInfoMapper.selectSno(payQuery.getOrder_no( ));    //根据订单号查询交易流水
        String sno = payQuery.getOrderNo();
        if (StringUtil.isEmpty(sno)) {
            payQuery.setErrmsg("无交易记录");
            payQuery.setStatus("2");
            return payQuery;
        }
        insertTra(presentQueryEs.getMchNo( ), presentQueryEs.getOutTransNo( ), presentQueryEs.getBizType( ));  //插入事物
        HttpClient client = HttpClientBuilder.create( ).build( ); //创建请求客户端
        HttpPost request = new HttpPost(config.getPay_url( )); //拼装请求xml并组装请求
        Document document = buildTradeStatusRequestXml(sno, config); //转账查询请求报文
        document.setXMLEncoding("gbk");
        String requestXml = document.asXML( );
        ByteArrayEntity requestEntity = null;
        log.info("存管通提现查询-请求报文如下：{}", XmlFormatter.formatXml(requestXml));
        try {
            requestEntity = new ByteArrayEntity(requestXml.getBytes("gbk"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace( );
            log.error("存管通提现查询-xml写入请求编码错误");
        }
        request.setEntity(requestEntity);
        request.setHeader("Content-Type", "application/x-fox");
        request.setHeader("Intensoft-Request-Sign", "YES");
        //发送请求并提取响应
        HttpResponse response = null;
        try {
            response = client.execute(request);
            //创建xml读取器并获取xml文件
            InputStreamReader reader = new InputStreamReader(response.getEntity( ).getContent( ), "gbk");
            BufferedReader bufferedReader = new BufferedReader(reader);
            String results = "";
            StringBuffer rbf = new StringBuffer();
            int tmp;
            while ((tmp = bufferedReader.read( )) != -1) {
                rbf.append((char) tmp);
            }
            results = rbf.toString();
            log.info("存管通提现查询-返回数据：{}", results);
            presentQuery = queryXmlToObject(results, payQuery);
            return presentQuery;
        } catch (Exception e) {
            e.printStackTrace( );
            log.error("存管通提现查询-异常：{}", e.toString( ));
        }
        return null;
    }

    /**
     * 转账交易状态查询
     */
    private Document buildTradeStatusRequestXml(String trunId, MchConfig mchConfig) {
        Document document = DocumentHelper.createDocument( );
        Element ele = DocumentHelper.createElement("FOX");
        Element ele1 = DocumentHelper.createElement("SIGNONMSGSRQV1");
        Element ele2 = DocumentHelper.createElement("SONRQ");
        ele2.addElement("DTCLIENT").setText(cn.hutool.core.date.DateUtil.now( ));
        ele2.addElement("CID").setText(mchConfig.getCid( ));
        ele2.addElement("USERID").setText(mchConfig.getUserid( ));
        ele2.addElement("USERPASS").setText(AES.getInstance( ).decrypt(mchConfig.getUserpass( )));  //AES解密
        ele2.addElement("GENUSERKEY").setText("N");
        ele2.addElement("APPID").setText("XYFIB");
        ele2.addElement("APPVER").setText("1000");
        ele1.add(ele2);
        Element ele3 = DocumentHelper.createElement("SECURITIES_MSGSRQV1");
        Element ele4 = DocumentHelper.createElement("XFERINQTRNRQ");
        ele4.addElement("TRNUID").setText(trunId);
        Element ele5 = DocumentHelper.createElement("XFERINQRQ");
        ele5.addElement("CLIENTREF").setText(trunId);
        ele4.add(ele5);
        ele3.add(ele4);
        ele.add(ele1);
        ele.add(ele3);
        document.add(ele);
        return document;
    }


    /**
     * 解析查询返回xml返回实体
     *
     * @param responseXml
     * @return
     * @throws Exception
     */
    public PresentQuery queryXmlToObject(String responseXml, PresentQuery presentQuery) throws Exception {
        Document document = DocumentHelper.parseText(responseXml);
        Element root = document.getRootElement( );

        Element ele = root.element("SIGNONMSGSRSV1");
        Element ele1 = ele.element("SONRS");
        Element ele2 = ele1.element("STATUS");
        Element ele3 = ele2.element("CODE");
        if (!"0".equals(ele3.getText( ))) {           //第一层返回状态
            Element messageEle = ele2.element("MESSAGE");
            log.info(messageEle.getText( ));
            return null;
        }
        Element ele6 = root.element("SECURITIES_MSGSRSV1");
        Element ele7 = ele6.element("XFERINQTRNRS"); //第一层无错误才有第二层
        Element ele9 = ele7.element("STATUS");
        Element ele10 = ele9.element("CODE");
        if (!"0".equals(ele10.getText( ))) {           //返回第二层的状态
            Element messageEle = ele9.element("MESSAGE");
            log.info(messageEle.getText( ));
            return null;
        }
        Element ele11 = ele7.element("XFERINQRS");
        Element ele12 = ele11.element("XFERLIST");
        Element ele21 = ele12.element("TO");
        if ("-1".equals(ele21.getText( ))) {  //没有交易记录
            presentQuery.setErrmsg("无交易记录");
            presentQuery.setStatus("2");
            return presentQuery;
        }
        Element ele13 = ele12.element("XFER");
        Element ele14 = ele13.element("XFERINFO");
        Element ele15 = ele14.element("TRNAMT");
        Element ele16 = ele13.element("XFERPRCSTS");
        Element ele17 = ele16.element("XFERPRCCODE");   //PAYOUT 成功   FAIL失败  PENDING：未知  WAIT_FOR_AUDIT：等待银行审核  PROCESSING：后台处理中 SEND_BACK：经办退回
        if ("PAYOUT".equals(ele17.getText( ))) {
            presentQuery.setStatus("1");
            MchAccnt mchAccnt = new MchAccnt( );
            mchAccnt.setMchAccntNo(presentQuery.getMchAccntNo( ));
            mchAccnt.setAccntType("mchsub");
            List<MchAccnt> resa = mchAccntMapper.selectMchAccnt(mchAccnt);
            if (resa.size( ) > 0) {
                Long accnt_amt_after = resa.get(0).getRemainAmt( );
                presentQuery.setAccntAmtAfter(AmountUtil.convertDollar2Cent(String.valueOf(accnt_amt_after)));    //成功返回账户余额，其他只返回明细
            }
        } else if ("FAIL".equals(ele17.getText( ))) {
            presentQuery.setStatus("2");
        } else {     //其他错误一律为未知
            presentQuery.setStatus("3");
        }
        presentQuery.setAmount(AmountUtil.convertDollar2Cent(ele15.getText( ))); //提现金额
        Element ele18 = ele16.element("DTXFERPRC");
        Element ele19 = ele14.element("ACCTTO");
        Element ele20 = ele19.element("ACCTID");
        presentQuery.setDtxferprc(ele18.getText( ));   //付款日期
        presentQuery.setCardNo(ele20.getText( ));     //银行卡号
        return presentQuery;
    }

}
